﻿using System;

namespace Dynamic.DataStructures
{
        
    /// <summary>
    /// Represents a variable size last-in-first-out collection of instances of the same arbitrary type.
    /// </summary>
    /// <typeparam name="T">Specifies the type of elements in the Stack.</typeparam>
    public class Stack<T> : IStack<T>
    {

        private int count;

        /// <summary>
        /// Gets the number of elements contained in the Stack.
        /// </summary>
        public int Count
        {
            get { return count; }
        }

        /// <summary>
        /// Node to the first element in the Stack.
        /// </summary>
        private Node<T> Head { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="Stack" /> class that is empty.
        /// </summary>
        public Stack()
        {
            Head = null;
            count = 0;
        }

        /// <summary>
        /// Inserts an object at the top of the Stack.
        /// </summary>
        /// <param name="item">The object to push onto the Stack.</param>
        public void Push(T item)
        {
            Node<T> node = new Node<T>();
            node.Information = item;
            node.Next = Head;
            Head = node;
            count++;
        }

        /// <summary>
        /// Removes and return the object at the top of the Stack.
        /// </summary>
        /// <exception cref="System.InvalidOperationException">Thrown when the Stack is empty.</exception>
        /// <returns>The first element of the Stack.</returns>
        public T Pop()
        {
            if (Head == null)
            {
                throw new InvalidOperationException("The stack is empty.");    
            }

            T information = Head.Information;
            Head = Head.Next;
            count--;

            return information;
        }

        /// <summary>
        /// Returns the object at the beginning of the Stack without removing it.
        /// </summary>
        /// <exception cref="System.InvalidOperationException">Thrown when the Stack is empty.</exception>
        /// <returns>The object at the beginning of the Stack.</returns>
        public T Peek()
        {
            if (Head == null)
            {
                throw new InvalidOperationException("The Stack is empty");
            }

            return Head.Information;
        }
    }
}
